﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms; // So we can show a messagebox.
using System.Drawing;
using System.Threading;
using System.Runtime.InteropServices; // To slow the preview mode to normal speed.


namespace AnaViewer
{
    /// <summary>
    /// An instance of this struct is passed GetClientRect API to get the size of the preview window.<br></br>
    /// A struct of ints that contains the location and size info for a screen region.<br></br>
    /// It is passed to GetClientRect API call as a ref variable so the members can be filled in.
    /// </summary>
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public RECT(int l, int t, int r, int b)
        {
            left = l;
            top = t;
            right = r;
            bottom = b;
        }
    }

	/// <summary>
	/// This class draws in the Display Properties Screensaver preview window exclusively.
	/// </summary>
	public class MiniPreview
	{
        /// <summary>
        /// 检测指定窗口是否可见。
        /// </summary>
        /// <param name="hWnd">指定窗口的 Handle。</param>
        /// <returns></returns>
        [DllImport("user32.DLL", EntryPoint = "IsWindowVisible")]
        private static extern bool IsWindowVisible(IntPtr hWnd);

        /// <summary>
        /// Declare an external API function call. A wrapper function calls this.
        /// </summary>
        /// <param name="hWnd"> Handle to the window being addressed.</param>
        /// <param name="rect"> Struct containing Size and Location to be filled with the client area size and loc.</param>
        /// <returns> true is success, otherwise false.</returns>
        [DllImport("user32.dll")]
        private static extern bool GetClientRect(IntPtr hWnd, ref RECT rect);



		/// <summary>
        /// 执行 屏保小窗口预览(mini preview)，直到 预览窗口 消失。
		/// </summary>
		public static void DoMiniPreview(int argHandle)
		{
            // Windows 显示属性窗口 的 Pointer。
			IntPtr ParentWindowHandle = new IntPtr(0);
            // 获取 Windows 显示属性对话框的 Pointer。
			ParentWindowHandle = (IntPtr) argHandle;
			RECT rect = new RECT();
            using (Graphics PreviewGraphic = Graphics.FromHwnd(ParentWindowHandle))//操作系统的 mini-preview 窗口
            {
                PreviewGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
                //获取预览窗口的区域
				GetClientRect(ParentWindowHandle, ref rect);
			    { // create a local scope to ensure that dt30SEconds goes out of scope as soon as unneeded.
				    // The parent window is never ready when preview is chosen, before we try to get the visible state. 
				    // So we must wait. I limit my waiting to 30 seconds. 
				    DateTime dt30Seconds = DateTime.Now.AddSeconds(30);
				    while (IsWindowVisible(ParentWindowHandle) == false)
				    {
					    if (DateTime.Now > dt30Seconds)//超时，退出
                            return;
					    Application.DoEvents();
				    }
			    } // After this point the dt30Seconds goes away.


                //双缓冲图片
                Bitmap screenBmp = new Bitmap(rect.right - rect.left, rect.bottom - rect.top, PreviewGraphic);
                Graphics g = Graphics.FromImage(screenBmp); // Create a Graphics object
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.Default;
                g.Clear(Color.Black);
                StringFormat centerFormat = new StringFormat();
                centerFormat.Alignment = StringAlignment.Center;
                centerFormat.LineAlignment = StringAlignment.Center;

                StringFormat rightTopFormat = new StringFormat();
                rightTopFormat.Alignment = StringAlignment.Far;
                rightTopFormat.LineAlignment = StringAlignment.Near;

                Font echoFont = Control.DefaultFont;
                Font timeFont = Control.DefaultFont;
                Image bgImage =Properties.Resources.ScreenSaverPreview;
                g.DrawImage(bgImage, new Rectangle(0, 0, screenBmp.Width, screenBmp.Height), new Rectangle(0, 0, bgImage.Width, bgImage.Height), GraphicsUnit.Pixel);
                //string echo = "语录阅览器\r\n\r\n不支持小窗口预览";
                //g.DrawString(echo, Control.DefaultFont, Brushes.White, new RectangleF(0, 0, screenBmp.Width, screenBmp.Height), centerFormat);

				while (IsWindowVisible(ParentWindowHandle) == true) //这时窗口可见
				{
                    // Slow down the mini-preview.
					Thread.Sleep(50);
					try
					{
                        g.Clear(Color.Black);
                        g.DrawImage(bgImage, new Rectangle(0, 0, screenBmp.Width, screenBmp.Height), new Rectangle(0, 0, bgImage.Width, bgImage.Height), GraphicsUnit.Pixel);
                        //g.DrawString(echo, echoFont, Brushes.White, new RectangleF(0, 0, screenBmp.Width, screenBmp.Height), centerFormat);
                        g.DrawString(DateTime.Now.ToLongTimeString(), timeFont, Brushes.Black, new RectangleF(0, 0, screenBmp.Width, screenBmp.Height), rightTopFormat);

                        PreviewGraphic.DrawImage(screenBmp, 0, 0, screenBmp.Width, screenBmp.Height); 
					}
					catch // the most likely reason we get an exception here is because
					{     // the user hits cancel button while drawing to mini-preview.
						break; // Either way we must get out of the program.
					}
					// NOTE: We don't need to clear the bitmap, because windows refreshing does this automatically.
					Application.DoEvents(); // Yield up some idle time and allow events to be processed.
				}
                
				screenBmp.Dispose();
				g.Dispose();
				PreviewGraphic.Dispose(); // We are done, trash this.
			}
		}
    }
}
